package com.ymy.thinking.in.spring.dependency.lookup;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

/**
 * 类型安全的依赖查找示例
 *
 * @author Ringo
 * @date 2021/9/1 21:55
 */
public class TypeSafeLookupDemo {

    public static void main(String[] args) {
        // 创建 IoC 容器
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        // 注册到 IoC 容器
        applicationContext.register(TypeSafeLookupDemo.class);
        // 开启 Spring 应用上下文
        applicationContext.refresh();

        // 单一类型查找
        displayBeanFactoryGetBean(applicationContext);                      // 不安全
        displayObjectFactoryGetObject(applicationContext);                  // 不安全
        displayObjectProviderGetIfAvailable(applicationContext);            // 安全

        // 集合类型查找
        displayListableBeanFactoryGetBeansOfType(applicationContext);       // 安全
        displayObjectProviderStream(applicationContext);                    // 安全

        // 关闭 Spring 应用上下文
        applicationContext.close();
    }

    // ObjectProvider#stream()
    private static void displayObjectProviderStream(BeanFactory beanFactory) {
        ObjectProvider<String> objectProvider = beanFactory.getBeanProvider(String.class);
        printBeansException("ObjectProvider#stream()", () -> objectProvider.stream().forEach(System.out::println));

    }

    // ListableBeanFactory#getBeansOfType()
    private static void displayListableBeanFactoryGetBeansOfType(ListableBeanFactory listableBeanFactory) {
        printBeansException("ListableBeanFactory#getBeansOfType()", () -> listableBeanFactory.getBeansOfType(String.class));
    }

    // ObjectProvider#getIfAvailable()
    private static void displayObjectProviderGetIfAvailable(BeanFactory beanFactory) {
        ObjectProvider<String> objectProvider = beanFactory.getBeanProvider(String.class);
        printBeansException("ObjectProvider#getIfAvailable()", objectProvider::getIfAvailable);
    }

    // ObjectFactory#getObject()
    private static void displayObjectFactoryGetObject(BeanFactory beanFactory) {
        // ObjectProvider 实现了 ObjectFactory
        ObjectFactory<String> objectFactory = beanFactory.getBeanProvider(String.class);
        printBeansException("ObjectFactory#getObject()", objectFactory::getObject);
    }

    // BeanFactory#getBean()
    private static void displayBeanFactoryGetBean(BeanFactory beanFactory) {
        printBeansException("BeanFactory#getBean()", () -> beanFactory.getBean("hello"));
    }

    // 打印异常
    private static void printBeansException(String source, Runnable runnable) {
        try {
            runnable.run();
            System.out.println("source from: " + source);
        } catch (BeansException e) {
            System.err.println(source + ": \t" + e.getMessage() + "\t 异常名字: " + e.getClass().getSimpleName());
        }
    }

}
